package com.zxy.supplier_system.server.utils.wechat.official

import com.fasterxml.jackson.module.kotlin.readValue
import com.zxy.supplier_system.server.utils.wechat.official.PKCS7Encoder.CHARSET
import jakarta.servlet.http.HttpServletRequest
import org.springframework.web.util.UriComponentsBuilder
import java.security.MessageDigest
import java.util.Arrays
import javax.crypto.Cipher
import javax.crypto.spec.IvParameterSpec
import javax.crypto.spec.SecretKeySpec
import kotlin.io.encoding.Base64
import kotlin.io.encoding.ExperimentalEncodingApi


data class WechatMessagePreValidateRequest(
    val signature: String,
    val timestamp: String,
    val nonce: String,
    val echostr: String
)

fun WechatOfficialAccountHelper.validateWechatMessagePreValidateRequest(request: WechatMessagePreValidateRequest): Boolean {
    if (wechatServerConfig == null) throw IllegalStateException("Wechat server config is not initialized")
    val string = listOf(wechatServerConfig.token, request.timestamp, request.nonce).sorted().joinToString("")
    return MessageDigest.getInstance("SHA-1").digest(string.toByteArray())
        .joinToString("") { "%02x".format(it) } == request.signature
}

@OptIn(ExperimentalEncodingApi::class)
fun WechatOfficialAccountHelper.parseWechatMessage(request: HttpServletRequest): Map<String, Any> {
    if (wechatServerConfig == null) throw IllegalStateException("Wechat server config is not initialized")
    val body = this.objectMapper.readValue<Map<String, Any>>(request.inputStream)
    val uri = UriComponentsBuilder.fromUriString(request.requestURI).build()
    val signature = uri.queryParams["msg_signature"]!!.first()
    val timestamp = uri.queryParams["timestamp"]!!.first()
    val nonce = uri.queryParams["nonce"]!!.first()
    val encrypt = body["Encrypt"] as String
    val string = listOf(encrypt,nonce,timestamp,wechatServerConfig.token).sorted().joinToString("")
    val sha1String = MessageDigest.getInstance("SHA-1").digest(string.toByteArray())
        .joinToString("") { "%02x".format(it) }
    if (signature!=sha1String){
        throw IllegalStateException("Signature is not valid")
    }
    val aesKey = Base64.decode(wechatServerConfig.encodingAESKey+"=")
    // 设置解密模式为AES的CBC模式
    val cipher = Cipher.getInstance("AES/CBC/NoPadding")
    val keySpec = SecretKeySpec(aesKey, "AES")
    val iv = IvParameterSpec(Arrays.copyOfRange(aesKey, 0, 16))
    cipher.init(Cipher.DECRYPT_MODE, keySpec, iv)

    // 使用BASE64对密文进行解码
    val encrypted = Base64.decode(encrypt)

    // 解密
    val original = cipher.doFinal(encrypted)
    val jsonContent: String
    val fromAppId: String
    try {
        // 去除补位字符
        val bytes = PKCS7Encoder.decode(original)!!

        // 分离16位随机字符串,网络字节序和appId
        val networkOrder = Arrays.copyOfRange(bytes, 16, 20)

        val jsonLength = recoverNetworkBytesOrder(networkOrder)

        jsonContent = String(Arrays.copyOfRange(bytes, 20, 20 + jsonLength), CHARSET)
        fromAppId = String(Arrays.copyOfRange(bytes, 20 + jsonLength, bytes.size),CHARSET)
    } catch ( e:Exception) {
        throw e
    }
    // appid不相同的情况
    if (fromAppId != appId) {
        error("App Id invalid")
    }

    return objectMapper.readValue(jsonContent)
}
private fun recoverNetworkBytesOrder(orderBytes: ByteArray): Int {
    var sourceNumber = 0
    for (i in 0 until 4) {
        sourceNumber = sourceNumber shl 8
        sourceNumber = sourceNumber or (orderBytes[i].toInt() and 0xFF)
    }
    return sourceNumber
}